package com.structure;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/*
* 调用构造方法
* 我们通常使用new操作符创建新的实例：

    Person p = new Person();
    如果通过反射来创建新的实例，可以调用Class提供的newInstance()方法：

    Person p = Person.class.newInstance();
    调用Class.newInstance()的局限是，它只能调用该类的public无参数构造方法。如果构造方法带有参数，或者不是public，就无法直接通过Class.newInstance()来调用。
    *
    *
    *
    通过Class实例获取Constructor的方法如下：

    getConstructor(Class...)：获取某个public的Constructor；
    getDeclaredConstructor(Class...)：获取某个Constructor；
    getConstructors()：获取所有public的Constructor；
    getDeclaredConstructors()：获取所有Constructor。
    注意Constructor总是当前类定义的构造方法，和父类无关，因此不存在多态的问题。

    调用非public的Constructor时，必须首先通过setAccessible(true)设置允许访问。setAccessible(true)可能会失败。

    小结
    Constructor对象封装了构造方法的所有信息；

    通过Class实例的方法可以获取Constructor实例：getConstructor()，getConstructors()，getDeclaredConstructor()，getDeclaredConstructors()；

    通过Constructor实例可以创建一个实例对象：newInstance(Object... parameters)； 通过设置setAccessible(true)来访问非public构造方法。
    *
* */
public class CallStructure {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        callStructure2();
    }

    //1:通过反射调用构造方法
    static private void callStructure1() throws IllegalAccessException, InstantiationException {
        Person xiaoming = Person.class.newInstance();
        xiaoming.name = "小明";
        System.out.println(xiaoming.name);
    }

    //2:通过反射调用有参数的构造方法
    //为了调用任意的构造方法，Java的反射API提供了Constructor对象，它包含一个构造方法的所有信息，可以创建一个实例。Constructor对象和Method非常类似，不同之处仅在于它是一个构造方法，并且，调用结果总是返回实例
    static private void callStructure2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取构造方法
        Constructor cons1 = Person.class.getConstructor(String.class);
        //调用构造方法
        Person xiaoli = (Person)cons1.newInstance("小李");
        System.out.println(xiaoli.name);
    }
}


class Person {
    public String name;

    public Person(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}